/**
 * c10_float_precision - 浮点精度问题：精度丢失与比较
 * 
 * 这是《Rust基础数据类型实战Cookbook》系列的第10个案例
 * 
 * 学习目标：
 * 1. 深入理解浮点数精度丢失的原因
 * 2. 掌握浮点数比较的正确方法
 * 3. 学习处理浮点运算误差的策略
 * 4. 理解累积误差的产生和影响
 * 5. 掌握epsilon比较法和相对误差比较法
 * 6. 学会在不同精度需求下选择合适的策略
 * 7. 了解浮点数在特定场景下的局限性
 * 
 * 主要内容：
 * - 浮点数精度丢失的数学原理
 * - 经典浮点误差问题的深入分析
 * - 累积误差的产生机制和影响
 * - 多种浮点数比较策略的实现
 * - 不同精度需求下的最佳实践
 * - 实际应用场景中的精度处理
 */

fn main() {
    println!("=== Rust 浮点精度问题与比较方法 ===\n");

    // 1. 浮点数精度丢失的基本原理
    demonstrate_precision_loss();
    
    // 2. 经典浮点误差问题
    demonstrate_classic_float_errors();
    
    // 3. 累积误差分析
    demonstrate_accumulation_errors();
    
    // 4. 绝对误差与相对误差
    demonstrate_error_types();
    
    // 5. Epsilon容差比较法
    demonstrate_epsilon_comparison();
    
    // 6. 相对误差比较法
    demonstrate_relative_comparison();
    
    // 7. ULP比较法
    demonstrate_ulp_comparison();
    
    // 8. 实际应用场景的精度处理
    demonstrate_practical_precision();
    
    println!("\n=== 总结 ===");
    println!("浮点数精度处理的核心原则：");
    println!("- 永远不要直接使用 == 比较浮点数");
    println!("- 选择合适的比较策略：epsilon、相对误差或ULP");
    println!("- 注意累积误差对长期计算的影响");
    println!("- 在金融等高精度场景考虑使用定点数库");
    println!("- 理解浮点数的局限性，合理设置精度预期");
}

/**
 * 演示浮点数精度丢失的基本原理
 */
fn demonstrate_precision_loss() {
    println!("1. 浮点数精度丢失的基本原理");
    println!("   理解为什么会发生精度丢失");
    
    // 1.1 二进制表示的局限性
    println!("\n1.1 二进制表示的局限性");
    
    // 十进制小数在二进制中的无限循环
    println!("十进制小数的二进制表示问题：");
    println!("  0.1 (十进制) 在二进制中是无限循环小数");
    println!("  类似于 1/3 在十进制中是 0.333... 的无限循环");
    
    let decimal_point_one = 0.1f64;
    let binary_representation = decimal_point_one.to_bits();
    
    println!("  0.1 的实际存储值: {:.17}", decimal_point_one);
    println!("  二进制位表示: {:064b}", binary_representation);
    println!("  十六进制表示: 0x{:016X}", binary_representation);
    
    println!("\n{}", "=".repeat(60));
}

/**
 * 演示经典浮点误差问题
 */
fn demonstrate_classic_float_errors() {
    println!("\n2. 经典浮点误差问题");
    println!("   深入分析常见的浮点运算误差");
    
    // 2.1 经典的 0.1 + 0.2 != 0.3
    println!("\n2.1 经典的 0.1 + 0.2 != 0.3 问题");
    
    let a: f64 = 0.1;
    let b: f64 = 0.2;
    let c: f64 = 0.3;
    let result: f64 = a + b;
    
    println!("基本运算：");
    println!("  a = 0.1, 实际值: {:.17}", a);
    println!("  b = 0.2, 实际值: {:.17}", b);
    println!("  c = 0.3, 实际值: {:.17}", c);
    println!("  a + b = {:.17}", result);
    
    println!("比较结果：");
    println!("  a + b == c: {}", result == c);
    println!("  差值: {:.2e}", (result - c).abs());
    
    // 连续除法和乘法
    let original = 1.0 / 3.0;
    let recovered = original * 3.0;
    
    println!("\n除法乘法的往返误差：");
    println!("  1.0 / 3.0 = {:.17}", original);
    println!("  (1.0 / 3.0) * 3.0 = {:.17}", recovered);
    println!("  与 1.0 的差值: {:.2e}", (recovered - 1.0_f64).abs());
    
    // 指数和对数的误差
    let values: [f64; 5] = [0.5, 1.0, 2.0, 10.0, 100.0];
    
    println!("\n指数和对数的往返误差：");
    for &val in &values {
        let log_result = val.ln();
        let exp_back = log_result.exp();
        let error = (exp_back - val).abs();
        let relative_error = error / val;
        
        println!("  {} → ln → exp: {:.15} (误差: {:.2e}, 相对误差: {:.2e})",
                val, exp_back, error, relative_error);
    }
    
    println!("\n{}", "=".repeat(60));
}

/**
 * 演示累积误差分析
 */
fn demonstrate_accumulation_errors() {
    println!("\n3. 累积误差分析");
    println!("   了解长期计算中误差如何累积和传播");
    
    // 3.1 简单累加的误差累积
    println!("\n3.1 简单累加的误差累积");
    
    let increment = 0.1;
    let iterations = 10;
    
    // 逐步累加
    let mut sum_accumulative = 0.0;
    println!("逐步累加 0.1：");
    for i in 1..=iterations {
        sum_accumulative += increment;
        let expected = increment * i as f64;
        let error = (sum_accumulative - expected).abs();
        let relative_error = error / expected;
        
        println!("  第{:2}次: {:.15} (期望: {:.15}, 误差: {:.2e}, 相对误差: {:.2e})",
                i, sum_accumulative, expected, error, relative_error);
    }
    
    // 直接计算对比
    let direct_calculation = increment * iterations as f64;
    println!("\n直接计算结果: {:.15}", direct_calculation);
    println!("累加结果:     {:.15}", sum_accumulative);
    println!("方法间差值:   {:.2e}", (sum_accumulative - direct_calculation).abs());
    
    println!("\n{}", "=".repeat(60));
}

/**
 * 演示绝对误差与相对误差的概念
 */
fn demonstrate_error_types() {
    println!("\n4. 绝对误差与相对误差");
    println!("   理解不同误差度量方式的特点和应用");
    
    // 4.1 绝对误差的概念和计算
    println!("\n4.1 绝对误差的概念");
    
    let test_pairs: [(f64, f64); 5] = [
        (1.0, 1.0001),
        (100.0, 100.01),
        (0.001, 0.001001),
        (1e6, 1e6 + 1.0),
        (1e-6, 1.001e-6),
    ];
    
    println!("绝对误差分析：");
    println!("  真值      | 测量值    | 绝对误差   | 误差评价");
    println!("  ----------|----------|-----------|----------");
    
    for &(true_val, measured_val) in &test_pairs {
        let absolute_error = (measured_val - true_val).abs();
        let error_category = match absolute_error {
            e if e < 1e-6 => "极小",
            e if e < 1e-3 => "很小",
            e if e < 1e-2 => "小",
            e if e < 0.1 => "中等",
            _ => "大",
        };
        
        println!("  {:<9} | {:<8} | {:<9.2e} | {}",
                format!("{:.3e}", true_val),
                format!("{:.3e}", measured_val),
                absolute_error,
                error_category);
    }
    
    // 4.2 相对误差的概念和计算
    println!("\n4.2 相对误差的概念");
    
    println!("相对误差分析：");
    println!("  真值      | 测量值    | 相对误差   | 误差评价");
    println!("  ----------|----------|-----------|----------");
    
    for &(true_val, measured_val) in &test_pairs {
        let relative_error = if true_val != 0.0 {
            ((measured_val - true_val) / true_val).abs()
        } else {
            f64::INFINITY
        };
        
        let error_category = match relative_error {
            e if e < 1e-6 => "极小",
            e if e < 1e-4 => "很小",
            e if e < 1e-3 => "小",
            e if e < 1e-2 => "中等",
            _ => "大",
        };
        
        println!("  {:<9} | {:<8} | {:<9.2e} | {}",
                format!("{:.3e}", true_val),
                format!("{:.3e}", measured_val),
                relative_error,
                error_category);
    }
    
    println!("\n{}", "=".repeat(60));
}

/**
 * 演示Epsilon容差比较法
 */
fn demonstrate_epsilon_comparison() {
    println!("\n5. Epsilon容差比较法");
    println!("   掌握使用固定容差进行浮点数比较");
    
    // 简单的epsilon比较函数
    fn epsilon_equal(a: f64, b: f64, epsilon: f64) -> bool {
        (a - b).abs() <= epsilon
    }
    
    // 测试经典的浮点误差问题
    let problematic_pairs = [
        (0.1 + 0.2, 0.3, "0.1 + 0.2 vs 0.3"),
        (1.0 / 3.0 * 3.0, 1.0, "1/3 * 3 vs 1.0"),
        (0.1 * 10.0, 1.0, "0.1 * 10 vs 1.0"),
    ];
    
    println!("\n基本epsilon比较测试：");
    let epsilon = 1e-10;
    
    for &(a, b, description) in &problematic_pairs {
        let direct_equal = a == b;
        let epsilon_equal_result = epsilon_equal(a, b, epsilon);
        let difference = (a - b).abs();
        
        println!("  {}: {} vs {}", description, a, b);
        println!("    直接比较: {} | Epsilon比较: {} | 差值: {:.2e}",
                direct_equal, epsilon_equal_result, difference);
    }
    
    let test_a = 1.0000001_f64;
    let test_b: f64 = 1.0;
    let actual_difference = (test_a - test_b).abs();
    
    println!("\n测试对象: {} vs {}, 实际差值: {:.2e}", test_a, test_b, actual_difference);
    
    let epsilon_candidates = [1e-9, 1e-8, 1e-7, 1e-6, 1e-5];
    println!("不同epsilon值的比较结果：");
    
    for &eps in &epsilon_candidates {
        let result = epsilon_equal(test_a, test_b, eps);
        let ratio = eps / actual_difference;
        
        println!("  ε = {:.2e}: {} (ε/差值 = {:.1}倍)", eps, result, ratio);
    }
    
    println!("\n{}", "=".repeat(60));
}

/**
 * 演示相对误差比较法
 */
fn demonstrate_relative_comparison() {
    println!("\n6. 相对误差比较法");
    println!("   学习基于相对误差的浮点数比较");
    
    // 简单相对误差比较
    fn relative_equal_simple(a: f64, b: f64, relative_epsilon: f64) -> bool {
        if a == b {
            true  // 处理相同值（包括无穷大）
        } else {
            let diff = (a - b).abs();
            let larger = a.abs().max(b.abs());
            if larger > 0.0 {
                diff / larger <= relative_epsilon
            } else {
                false  // 两个值都是零但不相等（不应该发生）
            }
        }
    }
    
    // 测试相对误差比较
    let test_cases: [(f64, f64, &str); 5] = [
        (1.0, 1.0001, "1.0 vs 1.0001"),
        (100.0, 100.01, "100.0 vs 100.01"),
        (1e-6, 1.0001e-6, "1e-6 vs 1.0001e-6"),
        (1e6, 1e6 + 100.0, "1e6 vs 1e6+100"),
        (0.0, 0.0, "0.0 vs 0.0"),
    ];
    
    let relative_eps = 1e-4;  // 0.01% 的相对误差
    println!("相对误差比较测试（相对误差阈值 = {:.2e}）：", relative_eps);
    
    for &(a, b, desc) in &test_cases {
        let abs_diff = (a - b).abs();
        let rel_diff = if a != 0.0 { abs_diff / a.abs() } else { f64::INFINITY };
        let result = relative_equal_simple(a, b, relative_eps);
        
        println!("  {}: {:.6e} vs {:.6e}", desc, a, b);
        println!("    绝对差值: {:.2e} | 相对差值: {:.2e} | 结果: {}", 
                abs_diff, rel_diff, result);
    }
    
    // 相对误差在不同数量级的表现
    let magnitude_tests: [(f64, f64); 5] = [
        (1e-12, 1e-12 * (1.0 + 1e-4)),
        (1e-6, 1e-6 * (1.0 + 1e-4)),
        (1.0, 1.0 * (1.0 + 1e-4)),
        (1e6, 1e6 * (1.0 + 1e-4)),
        (1e12, 1e12 * (1.0 + 1e-4)),
    ];
    
    println!("\n相同相对差值(0.01%)在不同数量级的表现：");
    let rel_threshold = 1e-3;  // 0.1% 阈值
    
    for &(base, modified) in &magnitude_tests {
        let abs_diff = (modified - base).abs();
        let rel_diff = abs_diff / base.abs();
        let passes = relative_equal_simple(base, modified, rel_threshold);
        
        println!("  数量级 {:.0e}: 绝对差值={:.2e}, 相对差值={:.2e}, 通过={}",
                base, abs_diff, rel_diff, passes);
    }
    
    println!("\n{}", "=".repeat(60));
}

/**
 * 演示ULP比较法
 */
fn demonstrate_ulp_comparison() {
    println!("\n7. ULP比较法");
    println!("   理解和应用ULP(Unit in the Last Place)比较法");
    
    println!("\n7.1 ULP的基本概念");
    
    println!("ULP (Unit in the Last Place) 是什么：");
    println!("- 表示浮点数的最小可表示增量");
    println!("- 两个相邻可表示浮点数之间的距离");
    println!("- 提供了最精确的浮点数比较基准");
    
    // ULP比较函数实现
    fn ulp_equal(a: f64, b: f64, max_ulp_diff: i64) -> bool {
        // 处理特殊值
        if a == b {
            return true;
        }
        
        if a.is_nan() || b.is_nan() {
            return false;
        }
        
        if a.is_infinite() || b.is_infinite() {
            return false;
        }
        
        // 将浮点数转换为有符号整数表示
        let a_bits = a.to_bits() as i64;
        let b_bits = b.to_bits() as i64;
        
        // 处理符号不同的情况
        if (a_bits < 0) != (b_bits < 0) {
            // 如果符号不同，只有两者都接近零时才可能相等
            return a.abs() < f64::MIN_POSITIVE && b.abs() < f64::MIN_POSITIVE;
        }
        
        // 计算ULP差异
        let ulp_diff = (a_bits - b_bits).abs();
        ulp_diff <= max_ulp_diff
    }
    
    // 计算两个浮点数之间的ULP距离
    fn ulp_distance(a: f64, b: f64) -> i64 {
        if a == b {
            return 0;
        }
        
        if a.is_nan() || b.is_nan() || a.is_infinite() || b.is_infinite() {
            return i64::MAX;
        }
        
        let a_bits = a.to_bits() as i64;
        let b_bits = b.to_bits() as i64;
        
        // 处理符号不同的情况
        if (a_bits < 0) != (b_bits < 0) {
            return i64::MAX;  // 符号不同通常认为距离很远
        }
        
        (a_bits - b_bits).abs()
    }
    
    // 7.2 ULP距离的计算和分析
    println!("\n7.2 ULP距离计算示例");
    
    let ulp_test_cases: [(f64, f64); 4] = [
        (1.0, 1.0000000000000002),  // 相邻的f64值
        (1.0, 1.0000000000000004),  // 2 ULP差距
        (0.1 + 0.2, 0.3),           // 经典误差问题
        (1e10, 1e10 + 2.0),         // 大数值范围
    ];
    
    println!("ULP距离分析：");
    for &(a, b) in &ulp_test_cases {
        let ulp_dist = ulp_distance(a, b);
        let abs_diff = (a - b).abs();
        let rel_diff = if a != 0.0 { abs_diff / a.abs() } else { f64::INFINITY };
        
        println!("  {:.17} vs", a);
        println!("  {:.17}", b);
        println!("    ULP距离: {}, 绝对差值: {:.2e}, 相对差值: {:.2e}", 
                ulp_dist, abs_diff, rel_diff);
        println!();
    }
    
    // 不同ULP阈值的比较效果
    let test_pair = (0.1 + 0.2, 0.3);
    let actual_ulp = ulp_distance(test_pair.0, test_pair.1);
    
    println!("测试对象: {:.17} vs {:.17}", test_pair.0, test_pair.1);
    println!("实际ULP距离: {}", actual_ulp);
    
    let ulp_thresholds = [1, 2, 4, 8, 16, 32, 64];
    println!("\n不同ULP阈值的比较结果：");
    
    for &threshold in &ulp_thresholds {
        let result = ulp_equal(test_pair.0, test_pair.1, threshold);
        println!("  ULP阈值 {:2}: {} ({})", 
                threshold, result, 
                if actual_ulp <= threshold { "通过" } else { "失败" });
    }
    
    println!("\n{}", "=".repeat(60));
}

/**
 * 演示实际应用场景的精度处理
 */
fn demonstrate_practical_precision() {
    println!("\n8. 实际应用场景的精度处理");
    println!("   在实际项目中选择和应用合适的精度处理策略");
    
    // 8.1 科学计算场景
    println!("\n8.1 科学计算场景");
    
    // 数值微分近似
    fn numerical_derivative(f: fn(f64) -> f64, x: f64, h: f64) -> f64 {
        (f(x + h) - f(x - h)) / (2.0 * h)
    }
    
    // 测试函数: f(x) = x^2, f'(x) = 2x
    fn test_function(x: f64) -> f64 {
        x * x
    }
    
    fn test_derivative(x: f64) -> f64 {
        2.0 * x
    }
    
    let x_test = 2.0;
    let analytical_derivative = test_derivative(x_test);
    
    println!("数值微分精度测试 (f(x) = x², x = {})：", x_test);
    println!("解析导数: {:.15}", analytical_derivative);
    
    let step_sizes = [1e-2, 1e-4, 1e-6, 1e-8, 1e-10];
    
    for &h in &step_sizes {
        let numerical = numerical_derivative(test_function, x_test, h);
        let error = (numerical - analytical_derivative).abs();
        let relative_error = error / analytical_derivative.abs();
        
        // 使用相对误差判断精度
        let acceptable = relative_error < 1e-10;
        
        println!("  h = {:.2e}: 数值导数 = {:.15}, 误差 = {:.2e}, 可接受 = {}",
                h, numerical, relative_error, acceptable);
    }
    
    // 8.2 金融计算场景
    println!("\n8.2 金融计算场景");
    
    // 复利计算
    fn compound_interest(principal: f64, rate: f64, periods: i32, time: f64) -> f64 {
        principal * (1.0 + rate / periods as f64).powf(periods as f64 * time)
    }
    
    // 连续复利（解析解）
    fn continuous_compound(principal: f64, rate: f64, time: f64) -> f64 {
        principal * (rate * time).exp()
    }
    
    let principal = 10000.0;
    let annual_rate = 0.05;
    let time_years = 10.0;
    
    let continuous_result = continuous_compound(principal, annual_rate, time_years);
    println!("复利计算精度分析（本金: ${:.2}, 年利率: {:.1}%, 时间: {} 年）：", 
            principal, annual_rate * 100.0, time_years);
    println!("连续复利（理论值）: ${:.6}", continuous_result);
    
    let compounding_periods = [1, 4, 12, 52, 365];  // 年、季、月、周、日
    
    for &periods in &compounding_periods {
        let discrete_result = compound_interest(principal, annual_rate, periods, time_years);
        let difference = (discrete_result - continuous_result).abs();
        
        // 金融计算通常要求绝对误差在分为单位
        let acceptable = difference < 0.01;  // 1分的精度
        
        let frequency = match periods {
            1 => "年复利",
            4 => "季复利", 
            12 => "月复利",
            52 => "周复利",
            365 => "日复利",
            _ => "其他",
        };
        
        println!("  {:6} ({}次/年): ${:.6}, 误差: ${:.4}, 可接受: {}",
                frequency, periods, discrete_result, difference, acceptable);
    }
    
    // 8.3 智能浮点比较函数
    println!("\n8.3 综合比较策略设计");
    
    // 智能浮点比较函数，根据数值特点选择最佳策略
    fn smart_float_equal(a: f64, b: f64, context: &str) -> bool {
        // 特殊值检查
        if a == b {
            return true;
        }
        
        if a.is_nan() || b.is_nan() || a.is_infinite() || b.is_infinite() {
            return false;
        }
        
        let abs_diff = (a - b).abs();
        
        // 根据应用场景选择策略
        match context {
            "scientific" => {
                // 科学计算：使用相对误差
                let larger = a.abs().max(b.abs());
                if larger > 1e-10 {
                    abs_diff / larger <= 1e-12
                } else {
                    abs_diff <= 1e-15
                }
            },
            "financial" => {
                // 金融计算：使用绝对误差（分为单位）
                abs_diff <= 0.001
            },
            "graphics" => {
                // 图形处理：使用适中的绝对误差
                abs_diff <= 1e-5
            },
            "gaming" => {
                // 游戏物理：较宽松的误差
                abs_diff <= 1e-4
            },
            _ => {
                // 默认：使用机器精度的倍数
                abs_diff <= f64::EPSILON * 100.0
            }
        }
    }
    
    // 测试不同场景下的比较策略
    let test_scenarios = [
        (1.0000000000001, 1.0, "scientific", "科学计算"),
        (100.001, 100.0, "financial", "金融计算"),
        (1.000001, 1.0, "graphics", "图形处理"),
        (1.0001, 1.0, "gaming", "游戏物理"),
        (1.0000000001, 1.0, "default", "默认场景"),
    ];
    
    println!("智能比较策略测试：");
    for &(val1, val2, context, description) in &test_scenarios {
        let result = smart_float_equal(val1, val2, context);
        let abs_diff = (val1 - val2).abs();
        
        println!("  {} ({:.12} vs {:.12}): 差值={:.2e}, 结果={}",
                description, val1, val2, abs_diff, result);
    }
    
    // 8.4 最佳实践总结
    println!("\n8.4 最佳实践总结");
    
    println!("浮点数精度处理的最佳实践：");
    
    println!("\n1. 选择策略指南：");
    println!("   🔬 科学计算: 相对误差法，高精度要求");
    println!("   💰 金融应用: 绝对误差法，考虑货币精度");
    println!("   🎮 游戏开发: 适中容差，平衡精度与性能");
    println!("   🎨 图形处理: GPU友好的f32，适当容差");
    
    println!("\n2. 实现准则：");
    println!("   ✅ 永远不要直接使用 == 比较浮点数");
    println!("   ✅ 根据应用场景选择合适的比较方法");
    println!("   ✅ 处理特殊值（NaN、无穷大、零值）");
    println!("   ✅ 考虑累积误差的影响");
    
    println!("\n3. 调试技巧：");
    println!("   🔍 打印实际浮点值的完整精度");
    println!("   🔍 分析二进制表示理解误差来源");
    println!("   🔍 监控长期计算中的误差累积");
    
    println!("\n{}", "=".repeat(60));
}
